package com.example.demo.thread.ch5;

import com.example.demo.thread.util.Debug;
import com.example.demo.thread.util.Tools;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 在Web应用中实现线程停止
 * @author: htc
 * @date: Created in 17:28 2019/1/14.
 */
public class ThreadManagementContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //创建并启动一个数据库监控线程
        AbstractMonitorThread databaseMonitorThread;
        databaseMonitorThread = new AbstractMonitorThread(2000) {
            @Override
            protected void doMonitor() {
                Debug.info("Monitoring database...");

                //模拟实际的时间消耗
                Tools.randomPause(1000);
            }
        };
        databaseMonitorThread.start();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        //停止所有登记的线程
        //语句1
        ThreadTerminationRegistry.INSTANCE.clearThreads();
    }

    /**
     * 抽象监控线程
     */
    static abstract class AbstractMonitorThread extends Thread {
        //监控周期
        private final long interval;

        /**
         * 线程停止标记
         */
        final AtomicBoolean terminationToken = new AtomicBoolean(false);

        /**
         * 线程初始化
         * @param interval
         */
        public AbstractMonitorThread(long interval) {
            this.interval = interval;

            //设置为守护线程
            setDaemon(true);
            ThreadTerminationRegistry.Handler handler;
            //语句 2
            handler = new ThreadTerminationRegistry.Handler() {
                @Override
                public void terminate() {
                    terminationToken.set(true);
                    AbstractMonitorThread.this.interrupt();
                }
            };
            //注册一个线程终止处理器
            //语句 3
            ThreadTerminationRegistry.INSTANCE.register(handler);
        }

        @Override
        public void run() {
            try {
                while (!terminationToken.get()) {
                    doMonitor();
                    Thread.sleep(interval);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            Debug.info("terminated:%s", Thread.currentThread());
        }

        /**
         * 子类覆盖该方法来实现监控逻辑
         */
        protected abstract void doMonitor();
    }
}
